'''
    对于网易音乐的JS逆向分析
'''
import requests
import execjs
from lxml import etree
import re

# 起始的url
url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='
# 请求头
headers = {
    'Cookie':'_ntes_nuid=399b5e331ec0413c5455353f1046477d; _iuqxldmzr_=32; NMTID=00OxQ0tD40btpDpiEN5qEuGUwKrZnkAAAGAfcSJcg; WNMCID=ikvmkb.1651377473502.01.0; WEVNSM=1.0.0; WM_TID=9FGbvXH8HeJFEQFVFQLFAG6joCCF2%2Bp%2B; _ntes_nnid=399b5e331ec0413c5455353f1046477d,1694477914286; ntes_utid=tid._.dNI4KmkFtAhAVlARUALQyZF5oUMNPBCs._.0; sDeviceId=YD-xxC57qOxaZ9ER1VVVBaRmV%2FBVOKVmHQ%2F; _gcl_au=1.1.1929627733.1709349287; JSESSIONID-WYYY=45rxoN2SQHlFSod6z%5CIkWcgyWitnbQofg5tdo%2BMqH%2Ba6xoy1T2Z9Tq7CrjVt7F%2Be2F9%2FUS%5CS0VUOdK1i8jsB3%5CfX%5CQax8QtB%2BWC9TOvVyM5ERU1kc1xiRaEi7c%2FaqdirlGxZlgfeiCYzztTHcRJ2boJD2%5C7dFPMJcrvtZyfeFDWPeuBf%3A1716081636947; WM_NI=BnpBU9fDW8zHJ6WrKsFEBcuoaQ%2B8hI5VlTD52Ak5%2B5zxUY33EaTJo9jT%2BVoFfz%2FHOA2mYkMJUFE3vaFnT%2B5ltMds096sjPlQnjYLQD9Ph3c8U3hP7wJFs9%2BPDsN4rd73Mkk%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6ee8ffc53b79c9687b644ab9a8eb3d55e928b9f86c521f88dbcbab15eb5b7bcd8c42af0fea7c3b92a82b2c0a3d833a69c99d9f9448aea9993ca79869b8e84f865a38fe5d9eb43f78aa4b5c73ff29fa5d6aa3fbaa89bbab23987bf9cabee33aa8ce5b7ee4ea6a6e1a9ce4bf2b3978cd042979a8bd4f56b86b29cccb868b893ac94b333f6ada6b1ef5baeb697add450fb90a8d4e23497eda8b1b67d8a9abddaaa5c88ad82d5f170f5ed838cea37e2a3; playerid=78955247',
    'Referer':'https://music.163.com/',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'
}

# 获取加密的信息
def getKey(id_list):
    offset = 0
    # 读取js文件，获取到params和encSecKey
    file = open('demo.js', 'r').read()
    yinyue_js = execjs.compile(file)
    for id in id_list:
        # print(id)
        params_seckey = yinyue_js.call('asrseaDict', id)
        data = {
            'params': params_seckey['encText'],
            'encSecKey': params_seckey['encSecKey']
        }
        try:
            resp = requests.post(url, headers=headers, data=data)
            # print(resp.text)
            json_data = resp.json()
            if ('data' in json_data and 'url' in json_data['data'][0] and
                    json_data['data'][0]['url'] is not None):

                music_url = json_data['data'][0]['url']
                # print(music_url)
                with open('爬取文件/music_url.csv',mode='a',encoding='utf-8') as file:
                    file.write(music_url + '\n')
                print('正在爬取',offset)
                offset = offset + 1
        except Exception as e:
            print('请求异常', e)
    print('写入完成')

# 通过传入榜单的url，获取歌曲的id和歌曲名字
def download_list(url):
    resp = requests.get(url,headers=headers).text
    pattern = r'href="/song\?id=(\d+)">(?P<name>.*?)</a>'
    music_data = re.findall(pattern,resp,re.S)
    # song里面包含着id和name
    return music_data

# 从download_list()方法中接收数据，返回id列表
def getId(music_data):
    id_list = []
    for item in music_data:
        id = item[0]
        id_list.append(id)
    # print(id_list)
    return id_list

# 从download_list()方法中接收数据，返回name列表
def getName(music_data):
    name_list = []
    for item in music_data:
        name = item[1]
        name_list.append(name)
    # print(name_list)
    return name_list

def getMusic(name_list):
    with open('爬取文件/music_url.csv',mode='r') as file:
        for url in file:
            download_url = url.strip()
            resp = requests.get(download_url,headers=headers).content
            for name in name_list:
                with open('爬取文件/歌曲/{}.mp3'.format(name),mode='wb') as f:
                    f.write(resp)
                print('歌曲写入',name)
    print('写入完成')

def main():
    # 榜单的url
    li_url = 'https://music.163.com/discover/toplist'
    # 接收歌单列表中的数据
    music_data = download_list(li_url)
    id_list = getId(music_data)
    name_list = getName(music_data)
    # getKey(id_list)
    getMusic(name_list)

if __name__ == '__main__':
    main()